home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software 2000
/
Software 2000 Volume 1 (Disc 1 of 2).iso
/
education
/
e077.dms
/
e077.adf
/
GRAVSIM
/
GRAVSIM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-07-12
|
41KB
|
1,379 lines
/*
T H E G R A V I T Y S I M U L A T O R
-------------------------------------------------
HISTORY:
=======
Here is a neat little project that started out as a ONE screen long
C program to simulate gravitational attraction amongst planets. A friend
and I thought of the idea for the program one day and we decided to write it.
Originally, you had to recompile the ENTIRE program to change the parameters
that govern , gravity, velocity, mass etc.!!!
Then I decided to allow it to read the parameters from an input file ! (WOW!)
Until many months later ...
I decided to use the idea in my Computer Graphics Animation project at
Adelaide Uni. What came next was 2 weeks of solid hacking to produce a program
that was MUCH EASIER to interact with !
This is my first really USEFUL program I have written, I hope you like it !.
By the way I have gone to GREAT PAINS to make this C program as READABLE
as possible to help all those new C hackers out there!
I just wish there were more programs as readable as this when I go my
Amiga 1000 2 years ago!.
THANKS:
=======
Special thanks must go to my friend ROBERT WOZNIAK, who designed the
ORIGINAL formulae ( of which I have improved slightly ) that govern the
planetary motion and to Michael Portmann, who supplied the idea of how to
enter the mass of the planets via mouse.
Title: THE GRAVITY SIMULATOR. Vr 1.50
Program by: Richard Frost (C) 1988,1989.
Adelaide, South Australia, Australia.
(The Grand Prix State!).
All code & I/O correct on: 10th August 1988
Final Menu Interface Correct on: 6th August 1988
Additions: Loading & saving files & new project menu,
November 24th 1988.
Status Bar on Screen Title during RECORD mode,
May 20th 1989.
Coloured Paths implemented succesfully on
May 21st, 3.30 AM.
(Yes AM! thats when REAL programmers work!!! )
Bug Fixes: Loading & saving files fixed on 29th Jan 1989.
*/
#include <stdio.h>
#include <exec/types.h>
#include <exec/tasks.h>
#include <exec/libraries.h>
#include <exec/devices.h>
#include <devices/keymap.h>
#include <graphics/copper.h>
#include <graphics/display.h>
#include <graphics/gfxbase.h>
#include <graphics/text.h>
#include <graphics/view.h>
#include <graphics/gels.h>
#include <graphics/regions.h>
#include <hardware/blit.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#define XMAX 639
#define XMIN 0
#define YMAX 512
#define YMIN 11
#define spriteXMAX 649
#define spriteXMIN -15
#define spriteYMAX 530
#define spriteYMIN -10
#define SCALE_FACTOR 128
#define SCREEN_WIDTH XMAX+1
#define SCREEN_HEIGHT YMAX+1
#define SCREEN_BITPLANES 2 /* have 4 colours */
#define StrGad 0 /* Gadget Label used in the requester */
#define PROJECT_MENU 0 /* Labels used for menu item events */
#define NEW_ITEM 0
#define LOAD_ITEM 1
#define SAVE_ITEM 2
#define QUIT_ITEM 3
#define PLANETS_MENU 1
#define PLACEPLANET_ITEM 0
#define REMOVEPLANET_ITEM 1
#define SETVELOCITY_ITEM 2
#define SETMASS_ITEM 3
#define PATHS_ITEM 4
#define ANIMATION_MENU 2
#define STARTANIM_ITEM 0
#define STOPANIM_ITEM 1
#define RESTARTANIM_ITEM 2
#define RECORDER_MENU 3
#define RECORDER_ON_ITEM 0
#define RECORDER_OFF_ITEM 1
#define PLAYBACK_ITEM 2
#define PLAYBACKSPEED_ITEM 3
#define FAST_ITEM 0
#define MEDIUM_ITEM 1
#define SLOW_ITEM 2
/* Flags to indicate coordinates types */
#define NewCoord 0 /* Indicates the mouse coordinate x,y is
to be used in rubber banding */
#define StartCoord 1 /* The start coordinate for the
velocity vector */
#define EndCoord 2 /* The end coordinate for the velocity vector.*/
extern struct Screen *OpenScreen();
extern struct Library *OpenLibrary();
extern struct Window *OpenWindow();
extern struct Message *GetMsg();
struct Library *IntuitionBase;
struct Library *GfxBase;
struct Window *NoBorder;
struct Screen *MyScreen;
struct IntuiMessage *message;
#define MAXplanets 6; /* MAXimum number of planets on the screen */
/* Various action flags */
BOOL PLACEPLANET = FALSE;
BOOL REMOVEPLANET = FALSE;
BOOL SETVELOCITY = FALSE;
BOOL SETMASS = FALSE;
BOOL RECORD = FALSE;
BOOL COMPUTEANIM = FALSE;
BOOL PLANETPATH = TRUE;
BOOL COLOURPATHS = TRUE;
char Default_Title[] = " THE GRAVITY SIMULATOR V1.50 By Richard Frost. © 1988, 1989",
Stats_Title[80];
SHORT PenColour =1;
int PlanetNum = 0; /* Number of planets currently on the screen */
/* ranges from 1..6 */
/* include all the menu defns. */
#include "GravSim.h"
/* sprite.h include. I could not be bothered */
/* making a new pre-include file just for this! */
#ifndef GRAPHICS_SPRITE_H
#define GRAPHICS_SPRITE_H
struct SimpleSprite
{
UWORD *posctldata;
UWORD height;
UWORD x,y; /* current position */
UWORD num;
};
#endif
/* ======================== Planet Sprite Definition ======================== */
UWORD PlanetData1[12] = {
0x0000,0x0000,
0x2000,0x3000,
0x4800,0x7000,
0x5800,0x6000,
0x1000,0x2000,
0x0000,0x0000
};
UWORD PlanetData2[12] = {
0x0000,0x0000,
0x2000,0x3000,
0x4800,0x7000,
0x5800,0x6000,
0x1000,0x2000,
0x0000,0x0000
};
UWORD PlanetData3[12] = {
0x0000,0x0000,
0x2000,0x3000,
0x4800,0x7000,
0x5800,0x6000,
0x1000,0x2000,
0x0000,0x0000
};
UWORD PlanetData4[12] = {
0x0000,0x0000,
0x2000,0x3000,
0x4800,0x7000,
0x5800,0x6000,
0x1000,0x2000,
0x0000,0x0000
};
UWORD PlanetData5[12] = {
0x0000,0x0000,
0x2000,0x3000,
0x4800,0x7000,
0x5800,0x6000,
0x1000,0x2000,
0x0000,0x0000
};
UWORD PlanetData6[12] = {
0x0000,0x0000,
0x2000,0x3000,
0x4800,0x7000,
0x5800,0x6000,
0x1000,0x2000,
0x0000,0x0000
};
struct SimpleSprite PlanetSprite[7]; /* Array of sprite definitions */
/* number of sprite moves stored: */
#define FILMLENGTH 6999
/* arrays for movie */
SHORT MoviePlanet[FILMLENGTH], /* the number of the planet for this data */
MovieScreenX[FILMLENGTH], /* screen coordinates for this planet sprite */
MovieScreenY[FILMLENGTH];
int frame = 0; /* the current frame position of the movie */
int DelayFactor = 0;
float X[7], /* X coordinate of the planet in world coordinates */
Y[7], /* Y coordinate of the planet in world coordinates */
Mass[7], /* The MASS of the planet */
Vx[7], /* The X velocity */
Vy[7], /* The Y velocity */
tempX[7], /* temporary variables used in the restart action */
tempY[7],
tempMass[7],
tempVx[7],
tempVy[7];
double sqrt();
/* Macro to Display the status bar on the screen title */
#define DisplayStats(c) sprintf(Stats_Title,"RECORDING SIMULATION... Maximum Frame: %-4d Current Frame: %-4d",FILMLENGTH+1,c);\
SetWindowTitles(NoBorder,-1,Stats_Title);
#define RestoreTitle() SetWindowTitles(NoBorder,-1,Default_Title)
/* ======================================================================== */
VOID CloseUpShop() /* Close down Screens, windows & menus.. */
{
int i;
/* free up the sprites .. */
for (i = 1 ; i <= 6 ; i++)
FreeSprite(i);
ClearMenuStrip(NoBorder);
CloseWindow(NoBorder);
CloseScreen(MyScreen);
}
/* ======================================================================== */
VOID OpenAll()
{
IntuitionBase = (struct Library *) OpenLibrary("intuition.library",0L);
if (IntuitionBase == NULL)
exit(FALSE);
GfxBase = (struct Library *) OpenLibrary("graphics.library",0L);
if (GfxBase == NULL)
exit(FALSE);
}
/* ======================================================================== */
VOID ClrScreen()
{
struct RastPort *r;
r= NoBorder->RPort;
SetAPen(r,0);
RectFill(r,0,0,XMAX,YMAX);
SetAPen(r,PenColour);
}
/* ======================================================================== */
VOID SetUpFrontEnd() /* Set up: Screen,Menus,Gadgets Requesters etc. */
{
UWORD i,
red,green,blue,
colour_reg;
UWORD *PlanetData_ptr;
USHORT SpriteNum;
SHORT s_id;
int delay;
struct ViewPort *Vp;
/* POWER WINDOWS doesn't know anything about PAL so I have to REMIND IT ..*/
/* Uncomment the following line IF Power Windows has a 640*200 screen */
/* NewScreenStructure.ViewModes = NewScreenStructure.ViewModes + LACE; */
NewScreenStructure.Width = NewWindowStructure1.Width = SCREEN_WIDTH;
NewScreenStructure.Height = NewWindowStructure1.Height = SCREEN_HEIGHT;
MyScreen = OpenScreen(&NewScreenStructure); /* Try to create the screen */
if (MyScreen != NULL)
{
NewWindowStructure1.Screen = MyScreen; /* assign screen pointer to the window */
NoBorder =OpenWindow(&NewWindowStructure1);
SetMenuStrip(NoBorder,&Menu1); /* Open up the Menus ! */
LoadRGB4(&MyScreen->ViewPort,Palette,4);
/* Set up the colour palette for the sprites */
for (colour_reg = 16 ; colour_reg < 32 ; colour_reg += 4 )
{
SetRGB4(&MyScreen->ViewPort,colour_reg,0,0,0);
SetRGB4(&MyScreen->ViewPort,colour_reg+1,8,6,4);
SetRGB4(&MyScreen->ViewPort,colour_reg+2,10,7,5);
SetRGB4(&MyScreen->ViewPort,colour_reg+3,13,9,6);
}
Vp = &MyScreen->ViewPort;
/* See if we can allocate the 6 sprites first ... */
for (SpriteNum = 1; SpriteNum <= 6 ; SpriteNum++)
{
/* Set the mass of that planet #spritenum = 0 */
Mass[SpriteNum] = 0;
if ( (s_id = GetSprite(&(PlanetSprite[SpriteNum]),SpriteNum)) != -1 )
{
/* if we can allocate the sprite... */
/* Initialize the planet sprite (x,y) pos ... */
X[SpriteNum] = s_id * 70 * SCALE_FACTOR;
Y[SpriteNum] = 600 * SCALE_FACTOR;
Mass[SpriteNum] = 0;
PlanetSprite[SpriteNum].x = s_id * 70 ;
PlanetSprite[SpriteNum].y = 600;
PlanetSprite[SpriteNum].height = 4;
/* For some strange reason the Amiga doesn't like having
multiple sprites sharing the same image structure !!!!
WHY is this !!!!!!!!!!!!!!!!!!!!?????
Thus I have declared each structure separately and the switch
below will ensure the pointer is pointing to the correct
one for sprite # SpriteNum */
switch(SpriteNum)
{
case 1: PlanetData_ptr = PlanetData1;
break;
case 2: PlanetData_ptr = PlanetData2;
break;
case 3: PlanetData_ptr = PlanetData3;
break;
case 4: PlanetData_ptr = PlanetData4;
break;
case 5: PlanetData_ptr = PlanetData5;
break;
case 6: PlanetData_ptr = PlanetData6;
break;
}
/* Display the sprite out of the viewing area */
/* so that when a user MAKES a planet, only a sprite */
/* repositioning is required. */
ChangeSprite(Vp,&(PlanetSprite[SpriteNum]),PlanetData_ptr);
}
else
printf("CANNOT ALLOCATE SPRITE #%ld\n",(LONG)(SpriteNum) );
} /* end for loop */
}
else
{
printf("CANT OPEN HIRES SCREEN!!!\n");
exit(FALSE);
}
}
/* ======================================================================== */
SHORT absolute(val)
SHORT val;
{
if (val <0)
return(-val);
else
return(val);
}
/* ======================================================================== */
VOID SetVelocityVector(pnum,x,y,stateflag)
LONG pnum,x,y,stateflag;
{
/* These variables are not destroyed on block exit
and are used to keep track of what state the program is in */
static LONG Xstart,Ystart,
Xold,Yold,planetnumber;
switch (stateflag)
{
case NewCoord: if ((Xold != x) || (Yold != y))
{
/* erase OLD line using COMPLEMENT mode*/
Move(NoBorder->RPort,Xstart,Ystart);
Draw(NoBorder->RPort,Xold,Yold);
/* Draw the new line */
Move(NoBorder->RPort,Xstart,Ystart);
Draw(NoBorder->RPort,x,y);
/* Remember where these coordinates are
so we can erase this line when the Mouse moves */
Xold = x;
Yold = y;
} break;
case StartCoord: /* Store the start point and old points */
planetnumber = pnum;
Xstart = x;
Ystart = y;
Xold = x + (long)Vx[planetnumber];
Yold = y + (long)Vy[planetnumber];
Move(NoBorder->RPort,Xstart,Ystart);
Draw(NoBorder->RPort,Xold,Yold);
break;
case EndCoord: /* The user released the LEFT mouse button
1) Draw the final vector,
vector LENGTH proportional to magnitude.
x & y displacements should be scaled
appropriately to produce Vx,Vy.
2) Update the velocity components
of the appropriate mass.
NOTE: This will leave the vectors still
on the screen.
Thus when the user selects START ANIMATION
in the menu, the screen is cleared.
*/
/* delete the old vector */
Move(NoBorder->RPort,Xstart,Ystart);
Draw(NoBorder->RPort,Xold,Yold);
/* draw the vector selected by the user */
SetDrMd(NoBorder->RPort,JAM1);
SetAPen(NoBorder->RPort,1);
Move(NoBorder->RPort,Xstart,Ystart);
Draw(NoBorder->RPort,x,y);
/* alter the velocity of that planet! */
Vx[planetnumber] = x - Xstart ;
Vy[planetnumber] = y - Ystart ;
break;
}
}
/* ======================================================================= */
VOID GravityAttract(M1,M2,deltaX,deltaY,vx,vy)
float M1,M2,deltaX,deltaY,*vx,*vy;
{
static float TimeStep; /* This is the delta Time step */
float F,
Fx,Fy,
r,ax,ay;
#define G 5000.0
/* First compute the separation distance R between the */
/* 2 masses M1 and M2, where:
deltaX = the X displacement between masses M1 & M2.
deltaY = the Y displacement between masses M1 & M2. */
#ifdef DEBUG
printf("\nIn Gravity attract.\n");
printf("delx,dely = %f,%f\n",deltaX,deltaY);
printf("M1,M2 = %f,%f\n",M1,M2);
printf("Vx,Vy = %f %f \n",*vx,*vy);
#endif
r = sqrt( (double) (deltaX*deltaX + deltaY*deltaY) ) ;
if (r < 2000 )
{
TimeStep = r * 0.04 + 1;
}
else
TimeStep = 80.0;
/* Next, compute the mutual force of attraction, F, between the */
/* 2 masses using the standard GRAVITY FORMULA */
F = G * M1 * M2/(r*r);
/* Now as the force vector between the 2 masses is parallel to the */
/* displacement vector between them, we can use proportions */
/* and similar triangles to evaluate the the magnitude of the */
/* X and Y components of F relative to the displacements deltaX */
/* and deltaY. */
Fx = F * deltaX/r;
Fy = F * deltaY/r;
/* The resultant acceleration of MASS 1 can be found by using */
/* Newton's First Law F = M * A . */
/* 'TimeStep' appears in this equation as it is used in the */
/* evaluation of velocity later on.*/
ax = TimeStep * Fx/M1;
ay = TimeStep * Fy/M1;
/* Use the equation: V2 = V1 + ACCELERATION * TIME */
/* NOTE: This equation is only valid for CONSTANT acceleration */
/* however accln. is not constant in real life gravity problems. */
/* In my program I use a relatively small delta Time */
/* increments, sufficiently small enough such that my program */
/* effectively integrates the changes in acceleration over time. */
/* The major problem with this theory is that when 2 planets */
/* are very close to each other the mutual force increases by */
/* an inverse square law and my program steps through time */
/* too quickly at this stage and the result is that when the */
/* masses pass each other they still have a large velocity */
/* as there was not enough time intervals in which either */
/* planet's velocity is reduced by force due to the the other.*/
*vx += ax;
*vy += ay;
#ifdef DEBUG
printf("out of Gravity attract.\n");
#endif
}
/* ======================================================================== */
VOID MovePlanets()
{
float x1,y1,
vx1,vy1,
xop,yop;
int xpos,ypos ;
WORD p,otherp;
USHORT class;
SHORT sx,sy;
ULONG code;
/* Store the initial values before we start ! */
for (p=1 ; p<=6 ; p++ )
{
tempX[p] = X[p];
tempY[p] = Y[p];
tempMass[p] = Mass[p];
tempVx[p] = Vx[p];
tempVy[p] = Vy[p];
}
if (RECORD)
{
DisplayStats(frame);
}
while (COMPUTEANIM)
{
for( p=1 ;p <= 6 ;p++)
{
/* for all planets 1...6 */
if (Mass[p] != 0) /* if the planet is on the screen then */
{
/* Find the overall force on planet 'p' */
/* due to all other planets 'otherp' on the screen */
/* ie. all those with non-zero mass */
for( otherp=1 ;otherp<= 6 ; otherp++)
{
if ((otherp != p) && (Mass[otherp] != 0))
{
/* obtain the new Vx and Vy velocities ... */
GravityAttract(Mass[p],
Mass[otherp],
X[otherp]-X[p],Y[otherp]-Y[p],
&Vx[p],&Vy[p]);
}
}
/* Excuse the following code, it is a remnant from the days
when I used Aztec 3.4a, which got very upset with arrays
used in complex expressions. */
X[p] += Vx[p];
Y[p] += Vy[p];
xpos = X[p] / SCALE_FACTOR ; /* 128 = SCALE_FACTOR */
ypos = Y[p] / SCALE_FACTOR ;
/* if the planet 'p' is not out of the screen range then move it */
if ((xpos > spriteXMIN && xpos < spriteXMAX) && (ypos > spriteYMIN && ypos < spriteYMAX))
{
sx = (SHORT)xpos;
sy = (SHORT)ypos;
/* If in record mode and not out of
film then record the position! */
if ( (RECORD) && frame < FILMLENGTH )
{
MovieScreenX[frame] = sx;
MovieScreenY[frame] = sy;
MoviePlanet[frame] = p;
frame++; /* Advance recorder to the next frame */
}
MoveSprite(&MyScreen->ViewPort,&PlanetSprite[p],sx,sy);
if (PLANETPATH)
{
if ((xpos > XMIN && xpos < XMAX) && (ypos > YMIN && ypos < YMAX))
/* Toggle the paths */
{
if (COLOURPATHS)
SetAPen(NoBorder->RPort,((p % 4) ? p : 1));
WritePixel(NoBorder->RPort,sx+6 ,sy+3);
}
}
}
} /* end if */
} /* end for loop */
if ( RECORD && (frame % 100 == 0) ) /* WARNING: leave the following { } in!! */
/* Display Stats is a MACRO!!! */
{
DisplayStats(frame);
}
/* See if the user hit the STOP button!!! */
while ( message=(struct IntuiMessage *) GetMsg(NoBorder->UserPort) )
{
/* If a message was recieved .... */
class = message->Class; /* Store the message class! */
code = message->Code; /* Store the code */
ReplyMsg(message);
if ( (class == MENUPICK) && (MENUNUM(code) != MENUNULL) )
{
if ((MENUNUM(code) == ANIMATION_MENU) && (ITEMNUM(code) == STOPANIM_ITEM))
{
COMPUTEANIM = FALSE;
break;
}
}
} /* end event while loop */
} /* End While loop */
if (RECORD)
{
DisplayStats(frame);
}
}
/* ======================================================================== */
VOID MakePlanet(xpos,ypos)
SHORT xpos,ypos;
{
USHORT scanplanet,
freeplanet;
PlanetNum++;
/* find a planet that is free to use ! */
for(scanplanet = 1 ; scanplanet <= 6 ; scanplanet++)
{
if (Mass[scanplanet] == 0) /* FOUND AN UNUSED PLANET! */
{
freeplanet = scanplanet;
break; /* exit the loop as we have found it! */
}
}
/* Display the sprite by moving that sprite into the viewing area */
MoveSprite(&MyScreen->ViewPort,&PlanetSprite[freeplanet],xpos,ypos);
Mass[freeplanet] = 20; /* default mass of the planet */
X[freeplanet] = xpos * SCALE_FACTOR;
Y[freeplanet] = ypos * SCALE_FACTOR;
Vx[freeplanet] = 0;
Vy[freeplanet] = 0;
}
/* ======================================================================== */
VOID DeletePlanet(Number)
SHORT Number;
{
MoveSprite(&MyScreen->ViewPort,&PlanetSprite[Number],70*Number,550);
Mass[Number] = 0; /* ZERO the mass of the planet */
/* This Deactivates a planet to ensure */
/* it is not used in the gravity evaluation */
PlanetNum--;
}
/* ======================================================================== */
PlanetTouched(xpos,ypos)
SHORT xpos,ypos;
{
USHORT delx,dely,num;
int planetfound = 0;
/* Software collision routine to detect a collision between the pointer */
/* and a given mass at xpos,ypos. */
for (num = 1; num <= 6; num++ )
{
delx = absolute( PlanetSprite[num].x + 4 - xpos );
dely = absolute( PlanetSprite[num].y + 4 - ypos );
if (delx < 5 && dely < 5)
{
planetfound = num;
break;
}
}
return(planetfound);
}
/* ======================================================================== */
VOID SetMass(pnum,x,y,stateflag)
LONG pnum,x,y,stateflag;
{
static struct IntuiText mesg;
static char NewMassString[7], OldMassString[7];
static int Xdrw,Ydrw;
static float PlanetMass;
int i;
switch(stateflag)
{
case StartCoord: mesg.FrontPen = 1;
mesg.BackPen = 0;
mesg.DrawMode = COMPLEMENT;
mesg.LeftEdge = 0;
mesg.TopEdge = 0;
mesg.ITextFont = NULL;
mesg.IText = NULL;
mesg.NextText = NULL;
Xdrw = x + 7; /* the coordinates of the string */
Ydrw = y;
PlanetMass = Mass[pnum];
/* init old string to the mass of that planet */
sprintf(OldMassString,"%d",(int)PlanetMass);
mesg.IText = (UBYTE *) OldMassString;
PrintIText(NoBorder->RPort,&mesg,Xdrw,Ydrw);
break;
case NewCoord: /* erase old string .. */
mesg.IText = (UBYTE *) OldMassString;
WaitTOF();
PrintIText(NoBorder->RPort,&mesg,Xdrw,Ydrw);
/* calculate the new mass size from the */
/* current mouse Y- coords. */
PlanetMass = (absolute(Ydrw - y) + 0.8)/0.6 ;
/* convert the float into a float string */
sprintf(NewMassString,"%d",(int)PlanetMass);
/* print new string .. */
mesg.IText = (UBYTE *) NewMassString;
WaitTOF();
PrintIText(NoBorder->RPort,&mesg,Xdrw,Ydrw);
/* Save to old string */
i = 0;
while ( ( OldMassString[i] = NewMassString[i] ) != '\0')
i++;
break;
case EndCoord: /* erase old string .. */
mesg.IText = (UBYTE *) OldMassString;
PrintIText(NoBorder->RPort,&mesg,Xdrw,Ydrw);
/* store the new mass for that planet */
Mass[pnum] = PlanetMass;
break;
}
}
/* ======================================================================== */
VOID PlayBack()
{
SHORT Number,sx,sy;
int CurrentFrame,i,del;
struct SimpleSprite TempSprite[7]; /* Temp Sprite posns */
ClrScreen();
/* save current sprite positions before the animation */
for (i = 1 ; i < 7 ; i++ )
TempSprite[i] = PlanetSprite[i];
/* REPLAY the ANIMATION! ... */
for ( CurrentFrame = 0 ; CurrentFrame < frame ; CurrentFrame++ )
{
/* do the delay as requested by the user */
for( del = 0 ; del < DelayFactor ; del++);
Number = MoviePlanet[CurrentFrame];
sx = MovieScreenX[CurrentFrame];
sy = MovieScreenY[CurrentFrame];
MoveSprite(&MyScreen->ViewPort,&PlanetSprite[Number],sx,sy);
if (PLANETPATH) /* Toggle the paths */
{
if (COLOURPATHS)
SetAPen(NoBorder->RPort,((Number % 4) ? Number : 1));
WritePixel(NoBorder->RPort,sx+6,sy+3);
}
}
/* Restore old current sprite positions before the animation */
for (i = 1 ; i < 7 ; i++ )
{
sx = TempSprite[i].x;
sy = TempSprite[i].y;
MoveSprite(&MyScreen->ViewPort,&PlanetSprite[i],sx,sy);
}
}
/* ======================================================================== */
VOID ResetValues()
{
int p,sx,sy;
/* Restore all planets to the states they were in BEFORE the last */
/* animation was computed. */
ClrScreen();
for (p=1 ; p<=6 ; p++ )
{
if (Mass[p])
{
sx = X[p] = tempX[p] ;
sy = Y[p] = tempY[p] ;
MoveSprite(&MyScreen->ViewPort,&PlanetSprite[p],sx/SCALE_FACTOR,sy/SCALE_FACTOR);
Mass[p] = tempMass[p] ;
Vx[p] = tempVx[p] ;
Vy[p] = tempVy[p] ;
}
}
}
/* ======================================================================== */
VOID TotalReset()
{
int p;
ClrScreen();
for (p= 1 ; p <= 6; p++ )
{
Mass[p] = 0;
Vx[p] = 0;
Vy[p] = 0;
MoveSprite(&MyScreen->ViewPort,&PlanetSprite[p],p*50,600);
}
PlanetNum = 0;
}
/* ======================================================================== */
char *GetFilename()
{
int j,looping = TRUE;
struct IntuiMessage *mes;
ULONG class;
static char filename[30];
while (looping)
{
if ( (mes = (struct IntuiMessage *) GetMsg(NoBorder->UserPort) ) == 0L)
{
Wait(1L<<NoBorder->UserPort->mp_SigBit);
continue;
}
class = mes->Class;
ReplyMsg(mes);
if (class == REQCLEAR)
looping = FALSE;
}
j = 0;
strcpy(filename,StringGadSIBuff);
while (filename[j] != 0)
{
if (filename[j] == '.')
break;
j++;
}
filename[j] = 0;
if (strlen(filename) != 0)
strcat(filename,".GSim");
return(filename);
}
/* ======================================================================== */
VOID LoadFile()
{
FILE *fopen(), *fp;
int i;
SHORT sx,sy;
char *filename;
/* Obtain the filename the user typed into the string gadget */
filename = GetFilename();
if ((fp = fopen(filename,"r")) != NULL) /* prepare to read the data file */
{
/* if everything is OK... */
ClrScreen();
TotalReset(); /* clear everything */
/* read in the X & y coordinates of the planets */
for (i=1; i <= 6; i++)
fscanf(fp,"%f%f",&X[i],&Y[i]);
for (i=1; i <= 6; i++)
fscanf(fp,"%f%f",&Vx[i],&Vy[i]);
for (i=1; i <= 6; i++)
{
fscanf(fp,"%f",&Mass[i]);
if (Mass[i]) PlanetNum++;
}
fclose(fp);
/* Re-position the sprites on the screen */
for (i=1; i<=6 ; i++)
{
sx = X[i]/SCALE_FACTOR;
sy = Y[i]/SCALE_FACTOR;
MoveSprite(&MyScreen->ViewPort,&PlanetSprite[i],sx,sy);
}
}
else
DisplayBeep(MyScreen); /* there was an error do a display beep ! */
}
/* ======================================================================== */
VOID SaveFile()
{
FILE *fopen(), *fp;
char *filename;
int i;
filename = GetFilename();
/* Obtain the filename the user typed into the string gadget */
/* prepare to read the data file */
if ((fp = fopen(filename,"w")) != NULL )
{
/* if everything is OK... */
/* read in the X & y coordinates of the planets */
for (i=1; i <= 6; i++)
fprintf(fp,"%f\t%f\n",X[i],Y[i]);
for (i=1; i <= 6; i++)
fprintf(fp,"%f\t%f\n",Vx[i],Vy[i]);
for (i=1; i <= 6; i++)
fprintf(fp,"%f\n",Mass[i]);
fclose(fp);
}
else
DisplayBeep(MyScreen); /* there was an error do a display beep ! */
}
/* ======================================================================== */
static VOID domenu(menu, item, subitem)
USHORT menu, item, subitem;
{
PLACEPLANET = FALSE;
REMOVEPLANET = FALSE;
SETVELOCITY = FALSE;
SETMASS = FALSE;
switch(menu)
{
case PROJECT_MENU :
{
switch (item)
{
case NEW_ITEM: TotalReset();
MakePlanet(320,256);
break;
case LOAD_ITEM: if ((Request(&RequesterStructure2,NoBorder)) == 1)
LoadFile();
else
printf("CANNOT OPEN REQUESTER!!\n");
break;
case SAVE_ITEM: if ((Request(&RequesterStructure2,NoBorder)) == 1)
SaveFile();
else
printf("CANNOT OPEN REQUESTER!!\n");
break;
case QUIT_ITEM: CloseUpShop();
printf("Thats all Folks!!!\n");
printf("Have a nice day.\n");
exit(0);
break;
}
}break;
case PLANETS_MENU :
{
switch(item)
{
case PLACEPLANET_ITEM: PLACEPLANET = TRUE;
break;
case REMOVEPLANET_ITEM: REMOVEPLANET = TRUE;
break;
case SETVELOCITY_ITEM: SETVELOCITY = TRUE;
SetAPen(NoBorder->RPort,PenColour);
break;
case SETMASS_ITEM: SETMASS = TRUE;
break;
case PATHS_ITEM: switch(subitem) {
case 0: PLANETPATH = TRUE;
break;
case 1: PLANETPATH = FALSE;
break;
case 2: COLOURPATHS = TRUE;
break;
case 3: COLOURPATHS = FALSE;
SetAPen(NoBorder->RPort,PenColour);
break;
}
break;
}
}break;
case ANIMATION_MENU :
{
switch(item)
{
case STARTANIM_ITEM:
ClrScreen();
COMPUTEANIM = TRUE;
MovePlanets();
break;
case STOPANIM_ITEM:
COMPUTEANIM = FALSE;
break;
case RESTARTANIM_ITEM:
/* RESET VALUES */
ResetValues();
break;
}
}break;
case RECORDER_MENU :
{
switch(item)
{
case RECORDER_ON_ITEM: RECORD = TRUE;
DisplayStats(frame);
frame = 0;
break;
case RECORDER_OFF_ITEM: RECORD = FALSE;
RestoreTitle();
break;
case PLAYBACK_ITEM: PlayBack();
break;
case PLAYBACKSPEED_ITEM: switch (subitem)
{
case 0: DelayFactor = 0;
break;
case 1: DelayFactor = 100;
break;
case 2: DelayFactor = 300;
break;
}
}
}
} /* end switch */
}
/* ============================ MAIN PROGRAM =========================== */
main ()
{
BOOL MouseMoved = FALSE,
PenDown = FALSE,
HitPlanet= FALSE;
USHORT class; /*Message class from Intuition */
ULONG code; /*Menu code from Intuition */
SHORT x,y,
PlanetNumber;
VOID OpenAll(),SetUpFrontEnd(),CloseUpShop(),
domenu(),
MakePlanet(),DeletePlanet(),MovePlanets(),
SetVelocityVector(),
SetMass();
OpenAll(); /* Open GfxBase & Intuition */
SetUpFrontEnd(); /* Initialize Screens, Windows, Menus, SPRITES etc. */
MakePlanet(100,256);
MakePlanet(400,256);
/* MAIN PROGRAM MAJOR LOOP! */
for (;;) /* INFINITE LOOP!! */
{
Wait(1L << NoBorder->UserPort->mp_SigBit); /* Wait until a signal occurs */
MouseMoved= FALSE;
while( message=(struct IntuiMessage *) GetMsg(NoBorder->UserPort) )
{
/* If a message was recieved .... */
class = message->Class; /* Store the message class! */
code = message->Code; /* Store the code */
x = NoBorder->MouseX; /* Store away the mouse positions */
y = NoBorder->MouseY;
ReplyMsg(message); /* And all importantly, TELL INTUITION
THAT YOU RECEIVED IT!! */
/* So that the message port can be cleared! */
/* Here is the 'case' statement which SORTS OUT all incoming MESSAGES */
switch (class)
{
/* HANDLE ALL EVENTS THAT INTUITION PASSES TO ME */
case MOUSEMOVE : MouseMoved = TRUE;
break;
case MENUPICK : if (MENUNUM(code) != MENUNULL)
domenu(MENUNUM(code),ITEMNUM(code),SUBNUM(code));
break;
/* If Left Mouse Button Pressed then it could
be meant for either:
1: 1st position (x,y) in placing planet
2: coord (x,y) of a planet to be deleted
Thus the Action Mode Flags sort this
out appropriately
*/
case MOUSEBUTTONS: if (code == SELECTDOWN)
{
PenDown = TRUE;
if (PLACEPLANET)
{
if (PlanetNum < 6)
MakePlanet(x,y);
else
DisplayBeep(MyScreen);
}
else
if (REMOVEPLANET)
{
/* Now check for a collision with */
/* the intuition pointer... */
/* if there was a collision ... */
if (PlanetNum > 1)
{
if ( (PlanetNumber = PlanetTouched(x,y)) != 0)
DeletePlanet(PlanetNumber);
}
else DisplayBeep(MyScreen);
}
else
if (SETVELOCITY)
{
if ( (PlanetNumber = PlanetTouched(x,y)) != 0)
{
HitPlanet = TRUE;
SetDrMd(NoBorder->RPort,COMPLEMENT);
SetVelocityVector(PlanetNumber,x,y,StartCoord);
}
}
else
if (SETMASS)
{
if ( (PlanetNumber = PlanetTouched(x,y)) != 0)
{
HitPlanet = TRUE;
SetMass(PlanetNumber,x,y,StartCoord);
}
}
} /* end 'if code == selectdown' */
else if (code == SELECTUP)
{
PenDown= FALSE;
if ((SETVELOCITY) && (HitPlanet))
{
SetVelocityVector(PlanetNumber,x,y,EndCoord);
HitPlanet = FALSE;
}
else
if ((SETMASS) && (HitPlanet))
{
SetMass(PlanetNumber,x,y,EndCoord);
HitPlanet = FALSE;
}
}
break;
}/* end Switch */
} /*end While Loop */
if (MouseMoved)
{
if (PenDown) /* if LEFT mouse button DOWN */
{
if (HitPlanet)
{
if (SETVELOCITY) /* and in SET VELOCITY MODE ..*/
SetVelocityVector(PlanetNumber,x,y,NewCoord);
else
if (SETMASS)
SetMass(PlanetNumber,x,y,NewCoord);
}
}
}
}/* end infinite FOR LOOP */
} /* THATS ALL FOLKS! */